package com.score;

import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class Controller  implements Runnable {
    private final int SIZE = 2048;
    private final int mMinSize;

    private Decoder mDecoderBanzou, mDecoderOrg;
    private boolean mIsOrg = false;
    private DataBuffer mDataBufferBanzou = new DataBuffer(40960);
    private DataBuffer mDataBufferOrg = new DataBuffer(40960);
    private Callback mCallback;
    private byte[] mBufferBanzou, mBufferOrg;
//    private KeyJni keyJni;

    private AudioTrack mAudioTrack;
    private boolean mIsStop;
    private int mPlaySize;

//    private EarEngine mEarEngine;
    private Context mContext;
    private FileThread mThread;
    private boolean mCanWriteRec;
    private int mPitch = 0;
    private byte[] mRecBuff = new byte[3528];
    private int mRecSize = 0;
    private int mBestSampleRate = 44100;
    private int mBestBufferSize;
    private boolean mPause;
    private boolean mCanEarback, mMarkCanEarback;
    private String mBanzouFilePath, mOrgFilePath, mRecFilePath, mMusicFilePath;

    public Controller(Context context, Callback callback, String banzouFilePath, String orgFilePath, String recFilePath, String musicFilePath) {
        mContext = context;
        mBanzouFilePath = copyFile();

        mRecFilePath = DirManager.getRecoderPath("banzou.id" + "_rec_" + System.currentTimeMillis() + ".pcm");
        mMusicFilePath = DirManager.getRecoderPath("banzou.id" + "_music_" + System.currentTimeMillis() + ".pcm");
        mOrgFilePath = copyFile2();

        Log.d("Controller", "Controller mBanzouFilePath=" + mBanzouFilePath + "  mOrgFilePath =" + mOrgFilePath + " recFilePath=" + recFilePath + ",musicFilePath=" + musicFilePath);

        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        if (am.isWiredHeadsetOn()) {
            mMarkCanEarback = mCanEarback = true;
        }

        boolean hasLowLatencyFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
        boolean hasProFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO);
        if (hasProFeature) {
            Constants.WAVE_DELAY_CUL = 20;
        } else if (hasLowLatencyFeature) {
            Constants.WAVE_DELAY_CUL = 45;
        } else {
            Constants.WAVE_DELAY_CUL = 65;
        }
        mBestBufferSize = 240;
        mPause = false;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            String bfs = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
            String bsr = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
            if (bsr != null) {
                mBestSampleRate = Integer.valueOf(bsr);
            }
            if (bfs != null) {
                mBestBufferSize = Integer.valueOf(bfs);
            }
            if (mBestSampleRate != 44100) {
//                Mp3Jni.createResample(mBestSampleRate, 1, 44100, 1);
            }
        }
        mPlaySize = 0;
        mCallback = callback;
        mBufferBanzou = new byte[SIZE];
        mBufferOrg = new byte[SIZE];
        if (mBanzouFilePath != null)
            mDecoderBanzou = new Decoder(context, mDataBufferBanzou, mBanzouFilePath);
        if (!TextUtils.isEmpty(mOrgFilePath))
            mDecoderOrg = new Decoder(context, mDataBufferOrg, mOrgFilePath);
//        mEarEngine = new EarEngine();
//        mEarEngine.createEngine(this, mBestSampleRate, 1, mBestBufferSize);
        mMinSize = AudioTrack.getMinBufferSize(44100,
                AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT);
        mAudioTrack = new AudioTrack(mCanEarback ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT, mMinSize, AudioTrack.MODE_STREAM);
        Constants.PLAY_DELAY += (int) (mMinSize / 176.4) * 2;
//        keyJni = new KeyJni(44100, 2);
    }
    private String copyFile() {
        String imageDir = DirManager.getImageDir();
        File file = new File(imageDir+"/伴奏.mp3");
        try {
            InputStream is = mContext.getAssets().open("十年/伴奏.mp3");
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buffer = new byte[4096];
            int len = -1;
            while ((len = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            fos.flush();
            fos.close();
            is.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
        return file.getAbsolutePath();
    }

    private String copyFile2() {
        String imageDir = DirManager.getImageDir();
        File file = new File(imageDir+"/原唱.mp3");
        try {
            InputStream is = mContext.getAssets().open("十年/原唱.mp3");
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buffer = new byte[4096];
            int len = -1;
            while ((len = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            fos.flush();
            fos.close();
            is.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
        return file.getAbsolutePath();
    }
    public void start() {
        mCanWriteRec = false;
        if(mDecoderBanzou==null)
            mCanWriteRec = true;
        mThread = new FileThread();
        mThread.start();
//        mEarEngine.start();
        if (mCanEarback)
            setEarback(mCanEarback);
        if (mDecoderBanzou != null)
            mDecoderBanzou.startPlay();
        if (mDecoderOrg != null)
            mDecoderOrg.startPlay();
        mAudioTrack.play();
        new Thread(this).start();
    }

    public void destroy() {
        mIsStop = true;
    }

    public void setOrg(boolean isOrg) {
        mIsOrg = isOrg;
    }

    public boolean setEarback(boolean back) {
        if (mCanEarback) {
//            mEarEngine.setEarback(back);
            return true;
        } else {
            Toast.makeText(mContext, "没插耳机不能启动耳返", Toast.LENGTH_SHORT).show();
            return false;
        }
    }

    public void setPitch(int pitch) {
        mPitch = pitch;
//        keyJni.setPitch(pitch);
    }

    public int getPitch() {
        return mPitch;
    }

    public void pause() {
        mPause = true;
//        Toast.makeText(mContext, "暂停播放", Toast.LENGTH_SHORT).show();
    }

    public void resume() {
        mPause = false;
        if (mCanEarback)
            setEarback(mCanEarback);
//        Toast.makeText(mContext, "恢复播放", Toast.LENGTH_SHORT).show();
    }

    public void setCanEarback(boolean can) {
        mCanEarback = can;
        Log.d("Controller", "setCanEarback mCanEarback==" + mCanEarback + ",mMarkCanEarback== " + mMarkCanEarback);
//        Toast.makeText(mContext, "setCanEarback mCanEarback==" + mCanEarback + ",mMarkCanEarback== " + mMarkCanEarback, Toast.LENGTH_SHORT).show();
    }

    public boolean getCanEarback() {
        return mCanEarback;
    }



    public boolean ismIsStop() {
        return mIsStop;
    }

    public boolean ismPause() {
        return mPause;
    }

    @Override
    public void run() {
        byte[] empty = new byte[SIZE];
        byte[] bf = new byte[SIZE];
        byte[] bf2 = new byte[SIZE];

        while (!mIsStop) {
            if (mPause) {
                if (mMarkCanEarback != mCanEarback) {
                    mMarkCanEarback = mCanEarback;
                    releaseAll();
//                    mEarEngine.createEngine(this, mBestSampleRate, 1, mBestBufferSize);
                    mAudioTrack = new AudioTrack(mCanEarback ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
                            AudioFormat.ENCODING_PCM_16BIT, mMinSize, AudioTrack.MODE_STREAM);
//                    mEarEngine.start();
                    mAudioTrack.play();
                }
                mAudioTrack.write(empty, 0, SIZE);
                continue;
            }
            boolean retBanzou = false;
            if (mDecoderBanzou != null)
                retBanzou = mDataBufferBanzou.getData(mBufferBanzou);
            boolean retOrg = false;
            if (mDecoderOrg != null)
                retOrg = mDataBufferOrg.getData(mBufferOrg);
            if (retBanzou) {
                for (int i = 0; i < SIZE / 4; i++) {
                    bf[i * 4 + 2] = bf[i * 4] = mBufferBanzou[i * 4];
                    bf[i * 4 + 3] = bf[i * 4 + 1] = mBufferBanzou[i * 4 + 1];
                }
//                Message.obtain(mThread.mHandler, 1, bf.clone()).sendToTarget();
                if (mIsOrg && retOrg) {
                    bf = new byte[SIZE];
                    for (int i = 0; i < SIZE / 4; i++) {
                        bf[i * 4 + 2] = bf[i * 4] = mBufferOrg[i * 4];
                        bf[i * 4 + 3] = bf[i * 4 + 1] = mBufferOrg[i * 4 + 1];
                    }

                }

                byte[] outBuf = null;
//                if (mPitch != 0) {
//                    outBuf = keyJni.process(bf, SIZE);
//                }

                if (outBuf != null) {
                    mAudioTrack.write(outBuf, 0, outBuf.length);
                    mPlaySize += outBuf.length;
                } else {
                    mAudioTrack.write(bf, 0, SIZE);
                    mPlaySize += SIZE;
                }
                if (!mCanWriteRec) {
                    mCanWriteRec = true;
                }

//                long time = (long) (1000f * mPlaySize / (44100 * 2 * 2)) - Constants.PLAY_DELAY;
                long time = (long) (1000f * mPlaySize / (44100 * 2 * 2)) - Constants.PLAY_DELAY;
                if (mCallback != null) {
                    mCallback.onPlayerTime(time);
                }
            }
        }

//        if (keyJni != null) {
//            keyJni.close();
//        }
        releaseAll();
        if (mDecoderBanzou != null)
            mDecoderBanzou.stopPlay();
        if (mDecoderOrg != null)
            mDecoderOrg.stopPlay();
        mThread.mHandler.sendEmptyMessage(-1);
//
//        if (mBestSampleRate != 44100) {
//            Mp3Jni.destroyResample();
//        }

    }

    private void releaseAll() {
        Log.d("Controller", "releaseAll===");
        if (mAudioTrack != null) {
            AudioTrack mReleaseAudioTrack = mAudioTrack;
            mAudioTrack = null;
            mReleaseAudioTrack.stop();
            mReleaseAudioTrack.release();
        }
//        if (mEarEngine != null) {
//            mEarEngine.release();
//        }
    }

    private int totalRecSize;

    class FileThread extends Thread {
        public Handler mHandler;
        private FileOutputStream fos1;
        private FileOutputStream fos2;

        @Override
        public void run() {
            super.run();
            try {
                fos1 = new FileOutputStream(mRecFilePath);
                fos2 = new FileOutputStream(mMusicFilePath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            Looper.prepare();
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    if (msg.what == -1) {
                        mHandler.getLooper().quit();
                    } else if (msg.what == 0) {
                        if (fos1 != null) {
//                            try {
//                                int len = msg.arg1;
////                                totalRecSize += len;
////                                byte[] ot = Mp3Jni.toStereo((byte[]) msg.obj, len);
////                                if (mCallback != null) {
////                                    double volume = calculateVolume1(ot, len);
////                                    mCallback.currentVolume(volume);
//////                                    mCallback.onRecodTime( (long) (totalRecSize / 88.2 / 2));
////                                }
////                                fos1.write(ot);
//                            } catch (IOException e) {
//                                e.printStackTrace();
//                            }
                        }
                    } else if (msg.what == 1) {
                        if (fos2 != null) {
                            try {
                                fos2.write((byte[]) msg.obj);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            };
            Looper.loop();
            try {
                if (fos1 != null) {
                    fos1.close();
                }
                if (fos2 != null) {
                    fos2.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private double calculateVolume1(byte[] buffer, int len) {
        double sumVolume = 0.0;

        double avgVolume = 0.0;

        double volume = 0.0;

        for (int i = 0; i < len; i += 2) {

            int v1 = buffer[i] & 0xFF;

            int v2 = buffer[i + 1] & 0xFF;

            int temp = v1 + (v2 << 8);// 小端

            if (temp >= 0x8000) {

                temp = 0xffff - temp;

            }

            sumVolume += Math.abs(temp);

        }

        avgVolume = sumVolume / buffer.length / 2;

        volume = Math.log10(1 + avgVolume) * 10;
        return volume;

    }

}
